package corn

import (
	"context"
	"fmt"
	"gitee.com/worklz/yunj-blog-go-micro-common/log"
	"gitee.com/worklz/yunj-blog-go-micro-common/util"
	"sync"
	"time"

	corn "github.com/robfig/cron/v3"
)

type TaskHandleError struct {
	Time    time.Time
	Latency uint64 // 耗时（单位：ms）
	Err     error
}

type TaskLastHandleResult struct {
	Time    time.Time
	Status  int
	Latency uint64 // 耗时（单位：ms）
	Err     error
}

// 任务接口
type TaskInterface interface {
	Name() string                               // 任务名称
	Desc() string                               // 任务描述
	Spec() string                               // 任务执行时间 - cron表达式
	LogPrefix() string                          // 日志前缀
	Timeout() time.Duration                     // 任务超时时间
	DefaultStartStatus() uint8                  // 默认启动状态
	GetStatus() uint8                           // 获取状态
	SetStatus(status uint8) error               // 设置状态
	SetRunAt(at *time.Time)                     // 设置开始时间
	GetRunAt() *time.Time                       // 获取开始时间
	IsRunning() bool                            // 是否正在处理
	SetPauseAt(at *time.Time)                   // 设置暂停时间
	GetPauseAt() *time.Time                     // 获取暂停时间
	GetLastHandleResult() *TaskLastHandleResult // 获取最近一次处理结果
	GetHandleErrors() []*TaskHandleError        // 获取近期处理错误（最近10次）
	Start() (err error)                         // 启动
	Stop()                                      // 停止
	Handler(ctx context.Context) error          // 任务处理函数
}

type Task struct {
	runCtx             context.Context       // 用于传递取消信号
	runCancel          context.CancelFunc    // 取消上下文的函数
	runMu              sync.Mutex            // 用于保护启动和停止操作
	status             uint8                 // 状态。对应task.Status
	runAt              *time.Time            // 处理运行时间
	pauseAt            *time.Time            // 处理暂停时间
	lastHandleResult   *TaskLastHandleResult // 最近一次处理结果
	lastHandleResultMu sync.Mutex            // 用于保护最近一次处理结果的设置
	handleErrors       []*TaskHandleError    // 近期处理错误（最近10次）
	cornEntryId        corn.EntryID          // corn任务id
	logPrefix          string                // 日志前缀
	taskInstance       TaskInterface         // 任务实例
}

// 编译时判断是否实现接口
var _ TaskInterface = (*Task)(nil)

// InitTaskInstance 初始化任务实例
func (t *Task) InitTaskInstance(taskInstance TaskInterface) {
	t.taskInstance = taskInstance
}

func (t *Task) Timeout() time.Duration {
	//TODO implement me
	panic("implement me")
}

func (t *Task) Handler(ctx context.Context) error {
	//TODO implement me
	panic("implement me")
}

func (t *Task) Name() string {
	panic("implement me")
}

func (t *Task) Desc() string {
	panic("implement me")
}

func (t *Task) Spec() string {
	panic("implement me")
}

// 获取状态
func (t *Task) GetStatus() uint8 {
	return t.status
}

// 设置处理状态
func (t *Task) SetStatus(status uint8) error {
	if _, ok := StatusEnum.IsValue(status); !ok {
		return fmt.Errorf("%s status %d is not valid", t.LogPrefix(), status)
	}
	t.status = status
	return nil
}

// 定义默认的启动状态（没有配置数据库状态时应用）
func (t *Task) DefaultStartStatus() uint8 {
	return STATUS_PAUSED
}

// 获取处理的运行时间
func (t *Task) GetRunAt() *time.Time {
	return t.runAt
}

// 设置处理的运行时间
func (t *Task) SetRunAt(at *time.Time) {
	t.runAt = at
	t.pauseAt = nil
}

// 是否处理运行中
func (t *Task) IsRunning() bool {
	return t.runAt != nil
}

// 获取处理的暂停时间
func (t *Task) GetPauseAt() *time.Time {
	return t.pauseAt
}

// 设置处理的暂停时间
func (t *Task) SetPauseAt(at *time.Time) {
	t.pauseAt = at
	t.runAt = nil
}

// 设置最近一次处理结果
func (t *Task) SetLastHandleResult(res *TaskLastHandleResult) {
	t.lastHandleResultMu.Lock()
	defer t.lastHandleResultMu.Unlock()
	t.lastHandleResult = res
}

// 获取最近一次处理结果
func (t *Task) GetLastHandleResult() *TaskLastHandleResult {
	return t.lastHandleResult
}

// 获取近期处理错误
func (t *Task) GetHandleErrors() []*TaskHandleError {
	return t.handleErrors
}

// 日志前缀
func (t *Task) LogPrefix() string {
	if t.logPrefix != "" {
		return t.logPrefix
	}
	name := t.taskInstance.Name()
	desc := t.taskInstance.Desc()
	if desc != "" || name != "" {
		t.logPrefix = fmt.Sprintf("定时任务[%s][%s]", name, desc)
	} else {
		t.logPrefix = fmt.Sprintf("定时任务[%s]", util.PackageFullName(t.taskInstance))
	}
	return t.logPrefix
}

// 开始处理
func (t *Task) Start() (err error) {
	t.runMu.Lock()
	defer t.runMu.Unlock()
	if t.taskInstance.GetStatus() == STATUS_RUNNING && t.IsRunning() {
		return fmt.Errorf("%s已启动！", t.LogPrefix())
	}
	// 初始化处理上下文
	t.runCtx, t.runCancel = context.WithCancel(context.Background())
	// 添加定时任务方法
	entryId, err := t.addCornFunc()
	if err != nil {
		return
	}
	t.cornEntryId = entryId

	currTime := time.Now().In(time.Local)
	err = t.SetStatus(STATUS_RUNNING)
	if err != nil {
		return
	}
	t.SetRunAt(&currTime)
	return
}

// 添加定时任务方法
func (t *Task) addCornFunc() (entryId corn.EntryID, err error) {
	entryId, err = Corn.AddFunc(t.taskInstance.Spec(), func() {
		select {
		case <-t.runCtx.Done():
			// 暂停
			return
		default:
			// 设置处理结果
			startTime := time.Now().In(time.Local)
			res := &TaskLastHandleResult{Time: startTime, Status: HANDLE_STATUS_PROGRESS}
			t.SetLastHandleResult(res)
			timeout := t.taskInstance.Timeout()
			done := make(chan bool)
			errChan := make(chan error)
			if timeout <= 0 {
				// 无超时时间
				func() {
					defer func() {
						if err := recover(); err != nil {
							errChan <- fmt.Errorf("panic: %v", err)
						}
					}()
					_ = t.taskInstance.Handler(t.runCtx)
					done <- true
				}()
			} else {
				// 有超时时间
				ctx, cancel := context.WithTimeout(context.Background(), timeout)
				defer cancel()
				go func(ctx context.Context) {
					defer func() {
						if err := recover(); err != nil {
							errChan <- fmt.Errorf("panic: %v", err)
						}
					}()
					select {
					case <-ctx.Done():
						errChan <- fmt.Errorf("执行超时！")
						return
					default:
						_ = t.taskInstance.Handler(t.runCtx)
						//panic("测试异常")
						done <- true
					}
				}(ctx)
			}

			select {
			case err := <-errChan:
				t.LogError("执行异常！", err)
				res.Status = HANDLE_STATUS_FAILED
				res.Err = err
			case <-done:
				t.LogInfo("执行完成！")
				res.Status = HANDLE_STATUS_COMPLETED
			}
			// 结果记录
			endTime := time.Now().In(time.Local)
			res.Latency = util.MsTimeDiff(startTime, endTime)
			// 判断是否错误
			if res.Status == HANDLE_STATUS_FAILED {
				currHandleError := &TaskHandleError{Time: endTime, Latency: res.Latency, Err: res.Err}
				if len(t.handleErrors) >= 10 {
					t.handleErrors = append(t.handleErrors[1:], currHandleError)
				} else {
					if t.handleErrors == nil {
						t.handleErrors = make([]*TaskHandleError, 0, 10)
					}
					t.handleErrors = append(t.handleErrors, currHandleError)
				}
			}
			t.SetLastHandleResult(res)
		}
	})
	t.LogInfo(fmt.Sprintf("EntryID[%d]开始调度！", entryId))
	return
}

// 停止处理
func (t *Task) Stop() {
	t.runMu.Lock()
	defer t.runMu.Unlock()
	t.runCancel()
	Corn.Remove(t.cornEntryId)
	currTime := time.Now().In(time.Local)
	_ = t.SetStatus(STATUS_PAUSED)
	t.SetPauseAt(&currTime)
	t.LogInfo(fmt.Sprintf("EntryID[%d]停止调度！", t.cornEntryId))
}

// 日志
func (t *Task) LogInfo(message string, withFields ...map[string]any) {
	log.Info(t.LogPrefix()+message, withFields...)
}

// 错误日志
func (t *Task) LogError(message string, err any, withFields ...map[string]any) {
	log.Error(t.LogPrefix()+message, err, withFields...)
}
